// Copyright (C) joyinter
// All rights reserved.
// 
// Author : Jiang Li
// Date   : 2004-8-24

#ifndef __SOCKBASE_H__
#define __SOCKBASE_H__

#pragma once

#include "refdata.h"
#include "singlelist.h"

class CJoySockData;
class CJoySockBase;

//##ModelId=44C4B5F60157
enum JoySockBlockingMode
{
	//##ModelId=44C4B5F60159
    SBM_None,
	//##ModelId=44C4B5F6015A
    SBM_Blocking,
	//##ModelId=44C4B5F60167
    SBM_Threading,
};

#pragma pack(push, 1)

//##ModelId=44C4B5F60177
class CJoySockSendData : public CJoyRefData
{
protected:
	//##ModelId=44C4B5F601B5
    template<typename T> friend void JoyConstruct(T*);
	//##ModelId=44C4B5F60187
    CJoySockSendData() {}
public:
	//##ModelId=44C4B5F60188
    int m_size;
	//##ModelId=44C4B5F60189
    void* GetData()
    {
        return this+1;
    }
	//##ModelId=44C4B5F6018A
    int GetDataSize() const
    {
        return m_size;
    }
	//##ModelId=44C4B5F60197
    void* GetBlock()
    {
        return &m_size;
    }
	//##ModelId=44C4B5F60198
    int GetBlockSize() const
    {
        return m_size + sizeof(m_size);
    }
	//##ModelId=44C4B5F6019A
    static CJoySockSendData* Create(int nSize);
	//##ModelId=44C4B5F601A5
    static CJoySockSendData* Create(const void* pBuf, int nSize);
};

//##ModelId=44C4B5F601C5
class CJoySockRecvData
{
public:
	//##ModelId=44C4B5F601D7
    CJoySockRecvData*   m_next;
	//##ModelId=44C4B5F601DA
    CJoySockData*   m_sockData;
	//##ModelId=44C4B5F601E5
    sockaddr_in m_from;
	//##ModelId=44C4B5F601E9
    int m_size;

	//##ModelId=44C4B5F601F4
    ~CJoySockRecvData();
	//##ModelId=44C4B5F601F5
    void* GetData()
    {
        return this+1;
    }
	//##ModelId=44C4B5F601F6
    int GetDataSize() const
    {
        return m_size;
    }
	//##ModelId=44C4B5F601F8
    static CJoySockRecvData* Create(CJoySockData* sockData, int nSize);
	//##ModelId=44C4B5F60205
    static CJoySockRecvData* Create(CJoySockData* sockData, const void* pBuf, int nSize);
};

#pragma pack(pop)

//##ModelId=44C4B5F60251
class CJoySockData : public CJoyRefData
{
public:
	//##ModelId=44C4B5F6035C
    class CSendItem
    {
    public:
		//##ModelId=44C4B5F60360
        CSendItem*  m_next;
		//##ModelId=44C4B5F6036C
        CJoySockSendData*   m_data;
		//##ModelId=44C4B5F60371
        sockaddr_in m_addr;
		//##ModelId=44C4B5F6037A
        CSendItem()
            : m_next(NULL), m_data(NULL)
        {
        }
		//##ModelId=44C4B5F6037B
        ~CSendItem()
        {
            if(m_data != NULL)
            {
                m_data->Release();
            }
        }
    };
	//##ModelId=44C4B5F6037C
    typedef CJoySingleList<CSendItem>   CSendList;

	//##ModelId=44C4B5F60262
    SOCKET  m_hSocket;

	//##ModelId=44C4B5F60266
    HANDLE      m_hRecvThread;
	//##ModelId=44C4B5F60267
    HANDLE      m_hSendThread;
	//##ModelId=44C4B5F60271
    HANDLE      m_hSendEvent;
	//##ModelId=44C4B5F60273
    CSendList   m_sendList;
	//##ModelId=44C4B5F60278
    CJoyCriticalSection m_sendingLock;
	//##ModelId=44C4B5F60281
    CJoyCriticalSection m_sendLock;
	//##ModelId=44C4B5F60286
    volatile CJoySockBase*   m_owner;

	//##ModelId=44C4B5F60290
    volatile bool    m_bCancelSend;
	//##ModelId=44C4B5F60291
    volatile bool    m_bClose;
	//##ModelId=44C4B5F60292
    volatile bool    m_bConnected;
	//##ModelId=44C4B5F6029F
    bool    m_bStream;
	//##ModelId=44C4B5F602A0
    bool    m_bBlock;
	//##ModelId=44C4B5F602A1
    bool    m_bBlocking;

	//##ModelId=44C4B5F602AF
    CJoySockData();
	//##ModelId=44C4B5F602B0
    virtual ~CJoySockData();

	//##ModelId=44C4B5F602BF
    CSendItem* PeekSendItem();

	//##ModelId=44C4B5F602C0
    virtual void PostRecvData(CJoySockRecvData* pData);
	//##ModelId=44C4B5F602C3
    virtual void PostSendItem(CSendItem* pItem);

	//##ModelId=44C4B5F602CE
    virtual void PostClose();

	//##ModelId=44C4B5F602D0
    void CreateThreads(int type, bool bSend = true, bool bRecv = true, bool bBlock = true);
	//##ModelId=44C4B5F602E0
    void ResumeThreads();
	//##ModelId=44C4B5F602E1
    void CloseThreads();
	//##ModelId=44C4B5F602E2
    void Attach(SOCKET s, bool bSend = true, bool bRecv = true, bool bBlock = true);

	//##ModelId=44C4B5F602FD
    bool Send(CJoySockSendData* pData, JoySockBlockingMode bm = SBM_None);
	//##ModelId=44C4B5F60300
    bool Send(const void* buf, int size, JoySockBlockingMode bm = SBM_None);
	//##ModelId=44C4B5F60310
    bool SendTo(const sockaddr_in& addr, CJoySockSendData* pData);
	//##ModelId=44C4B5F6031E
    bool SendTo(const sockaddr_in& addr, const void* buf, int size);

	//##ModelId=44C4B5F6032D
    virtual CJoySockData* CreateData(int type, const sockaddr_in& addr, bool bSend = true, bool bRecv = true, bool bBlock = true);
	//##ModelId=44C4B5F6033F
    virtual CJoySockData* CreateData(SOCKET s, bool bSend = true, bool bRecv = true, bool bBlock = true);
	//##ModelId=44C4B5F6034F
    virtual CJoySockData* OnCreateData();
};

//##ModelId=44C4B5F603B9
class CJoySockBase
{
protected:
    friend class CJoySocketTool;

	//##ModelId=44C4B5F603C9
    CJoySockData*   m_data;
	//##ModelId=44C4B5F603CD
    HANDLE  m_hConnectThread;

	//##ModelId=44C4B5F603D8
    virtual void OnRecvData(CJoySockRecvData& data);
	//##ModelId=44C4B5F603DB
    virtual void OnClose();
	//##ModelId=44C4B5F603DD
    virtual void OnConnect(int err);
	//##ModelId=44C4B5F70001
    virtual void OnAttach(CJoySockData* pData);
	//##ModelId=44C4B5F70004
    virtual CJoySockData* OnCreateData();

public:
	//##ModelId=44C4B5F70006
    CJoySockBase(void);
	//##ModelId=44C4B5F7000F
    virtual ~CJoySockBase(void);

	//##ModelId=44C4B5F70012
    void Attach(CJoySockData* pData);
	//##ModelId=44C4B5F70014
    void SetData(CJoySockData* pData);
	//##ModelId=44C4B5F7001F
    bool Create(int type, const sockaddr_in& addr, bool bSend = true, bool bRecv = true, bool bBlock = true);
	//##ModelId=44C4B5F70025
    bool Create(int nType, int nPort);
	//##ModelId=44C4B5F70030
    bool Connect(const sockaddr_in& addr);
	//##ModelId=44C4B5F70032
    bool Connect(PCSTR pszIP, int nPort);

	//##ModelId=44C4B5F7003E
    CJoySockData* CreateData(int type, const sockaddr_in& addr, bool bSend = true, bool bRecv = true, bool bBlock = true);
	//##ModelId=44C4B5F7004E
    CJoySockData* CreateData(SOCKET s, bool bSend = true, bool bRecv = true, bool bBlock = true);

	//##ModelId=44C4B5F70053
    virtual void Close();

	//##ModelId=44C4B5F7005E
    int GetLastError() const
    {
        int e = WSAGetLastError();
        return e;
    }
	//##ModelId=44C4B5F70060
    CJoySockData* GetSockData() const
    {
        return m_data;
    }

    //static CString AddressToString(const sockaddr_in& addr);
	//##ModelId=44C4B5F70062
    static void MakeAddress(sockaddr_in& addr, PCSTR pszIP, int nPort);

	//##ModelId=44C4B5F7006E
    bool Send(CJoySockSendData* pData);
	//##ModelId=44C4B5F70070
    bool Send(const void* buf, int size);
	//##ModelId=44C4B5F70073
    bool SendTo(const sockaddr_in& addr, CJoySockSendData* pData);
	//##ModelId=44C4B5F7007F
    bool SendTo(const sockaddr_in& addr, const void* buf, int size);

	//##ModelId=44C4B5F70083
    void SetNoTcpDelay(bool bNoDelay);
};

#endif  // __SOCKBASE_H__
